#ifndef COFF_H
#define COFF_H

#define IMAGE_SIZEOF_SHORT_NAME 8
#define CST_FUNC 0x20
#define CST_NOTFUNC 0

enum image_File_Machine {
    IMAGE_FILE_MACHINE_UNKNOWN = 0,
    IMAGE_FILE_MACHINE_AM33 = 0x1d3,
    IMAGE_FILE_MACHINE_AMD64 = 0x8664,
    IMAGE_FILE_MACHINE_ARM = 0x1c0,
    IMAGE_FILE_MACHINE_EBC=0xebc,
    IMAGE_FILE_MACHINE_I386 = 0x14c,
    IMAGE_FILE_MACHINE_IA64 = 0x200,
    IMAGE_FILE_MACHINE_M32R = 0x9041,
    IMAGE_FILE_MACHINE_MIPS16 = 0x266,
    IMAGE_FILE_MACHINE_MIPSFPU = 0x366,
    IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466,
    IMAGE_FILE_MACHINE_POWERPC = 0x1f0,
    IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1,
    IMAGE_FILE_MACHINE_R4000 = 0x166,
    IMAGE_FILE_MACHINE_SH3 = 0x1a2,
    IMAGE_FILE_MACHINE_SH3DSP = 0x1a3,
    IMAGE_FILE_MACHINE_SH4 = 0x1a6,
    IMAGE_FILE_MACHINE_SH5 = 0x1a8,
    IMAGE_FILE_MACHINE_THUMB = 0x1c2,
    IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169
};

enum image_sectionNumber{
    IMAGE_SYM_UNDEFINED = 0,
    IMAGE_SYM_ABSOLUTE = -1,
    IMAGE_SYM_DEBUG = -2
};

enum image_StorageClass {
    IMAGE_SYM_CLASS_END_OF_FUNCTION = -1,
    IMAGE_SYM_CLASS_NULL = 0,
    IMAGE_SYM_CLASS_AUTOMATIC = 1,
    IMAGE_SYM_CLASS_EXTERNAL = 2,
    IMAGE_SYM_CLASS_STATIC = 3,
    IMAGE_SYM_CLASS_REGISTER = 4,
    IMAGE_SYM_CLASS_EXTERNAL_DEF = 5,
    IMAGE_SYM_CLASS_LABEL = 6,
    IMAGE_SYM_CLASS_UNDEFINED_LABEL = 7,
    IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8,
    IMAGE_SYM_CLASS_ARGUMENT = 9,
    IMAGE_SYM_CLASS_STRUCT_TAG = 10,
    IMAGE_SYM_CLASS_MEMBER_OF_UNION = 11,
    IMAGE_SYM_CLASS_UNION_TAG = 12,
    IMAGE_SYM_CLASS_TYPE_DEFINITION = 13,
    IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14,
    IMAGE_SYM_CLASS_ENUM_TAG = 15,
    IMAGE_SYM_CLASS_MEMBER_OF_ENUM = 16,
    IMAGE_SYM_CLASS_REGISTER_PARAM = 17,
    IMAGE_SYM_CLASS_BIT_FIELD = 18,
    IMAGE_SYM_CLASS_BLOCK = 100,
    IMAGE_SYM_CLASS_FUNCTION = 101,
    IMAGE_SYM_CLASS_END_OF_STRUCT = 102,
    IMAGE_SYM_CLASS_FILE = 103,
    IMAGE_SYM_CLASS_SECTION = 104,
    IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105,
    IMAGE_SYM_CLASS_CLR_TOKEN = 107
};

enum image_characteristics
{
    IMAGE_SCN_TYPE_NO_PAD = 0x00000008,
    IMAGE_SCN_CNT_CODE = 0x00000020,
    IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040,
    IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080,
    IMAGE_SCN_LNK_OTHER = 0x00000100,

    IMAGE_SCN_LNK_INFO = 0x00000200,
    IMAGE_SCN_LNK_REMOVE = 0x00000800,
    IMAGE_SCN_LNK_COMDAT = 0x00001000,
    IMAGE_SCN_GPREL = 0x00008000,
    IMAGE_SCN_MEM_PURGEABLE = 0x00020000,
    IMAGE_SCN_MEM_16BIT = 0x00020000,
    IMAGE_SCN_MEM_LOCKED = 0x00040000,
    IMAGE_SCN_MEM_PRELOAD = 0x00080000,
    IMAGE_SCN_ALIGN_1BYTES = 0x00100000,
    IMAGE_SCN_ALIGN_2BYTES = 0x00200000,
    IMAGE_SCN_ALIGN_4BYTES = 0x00300000,
    IMAGE_SCN_ALIGN_8BYTES = 0x00400000,
    IMAGE_SCN_ALIGN_16BYTES = 0x00500000,
    IMAGE_SCN_ALIGN_32BYTES = 0x00600000,
    IMAGE_SCN_ALIGN_64BYTES = 0x00700000,
    IMAGE_SCN_ALIGN_128BYTES = 0x00800000,
    IMAGE_SCN_ALIGN_256BYTES = 0x00900000,
    IMAGE_SCN_ALIGN_512BYTES = 0x00A00000,
    IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000,
    IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000,
    IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000,
    IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000,
    IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000,
    IMAGE_SCN_MEM_DISCARDABLE = 0x02000000,
    IMAGE_SCN_MEM_NOT_CACHED = 0x04000000,
    IMAGE_SCN_MEM_NOT_PAGED = 0x08000000,
    IMAGE_SCN_MEM_SHARED = 0x10000000,
    IMAGE_SCN_MEM_EXECUTE = 0x20000000,
    IMAGE_SCN_MEM_READ = 0x40000000,
    IMAGE_SCN_MEM_WRITE = 0x80000000
};

typedef char BYTE;
typedef int DWORD;
typedef short WORD;

typedef struct _IMAGE_SECTION_HEADER
{
    BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
    union
    {
        DWORD PhysicalAddress;
        DWORD VirtualSize;
    } Misc;
    DWORD VirtualAddress;
    DWORD SizeOfRawData;
    DWORD PointerToRawData;
    DWORD PointerToRelocations;
    DWORD PointerToLinenumbers;
    WORD NumberOfRelocations;
    WORD NumberOfLinenumbers;
    DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

/*节结构定义*/
typedef struct Section
{
    int data_offset;         // 当前数据偏移位置
    char *data;              // 节数据
    int data_allocated;      // 分配内存空间
    char index;              // 节序号
    struct Section *link;    // 关联的其它节，符号节关联字符串节
    int *hashtab;            // 哈希表,只用于存储符号表
    IMAGE_SECTION_HEADER sh; // 节头
} Section;

typedef struct CoffSym
{
    DWORD Name;
    DWORD Next;
    DWORD Value;
    short SectionNumber;
    WORD Type;
    BYTE StorageClass;
    BYTE NumberOfAuxSymbols;
} CoffSym;


// 重定位结构体
typedef  struct CoffReloc{
    DWORD offset;  //在对应段的偏移量（从0开始）
    DWORD  cfsym;  //符号在符号表的索引(从0开始)，判断需要重定位的是哪个符号
    BYTE  section;  //在哪个段进行重定位
    BYTE  type;   //重定位的类型
}CoffReloc;


typedef struct _IMAGE_FILE_HEADER {
    WORD  Machine;
    WORD  NumberOfSections;
    DWORD TimeDateStamp;
    DWORD PointerToSymbolTable;
    DWORD NumberOfSymbols;
    WORD  SizeOfOptionalHeader;
    WORD  Characteristics;
}IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER;



Section *section_new(char *name, int Characteristics);
void section_realloc(Section *sec, int new_size);
void *section_ptr_add(Section *sec, int increment);
Section *new_coffsym_section(char *symtab_name, int Characteristics, char *strtab_name);
int coffsym_add(Section *symtab, char *name, int val, int sec_index, short type, char StorageClass);
void coffsym_add_update(Symbol *s, int val, int sec_index, short type, char StorageClass);
char *coffstr_add(Section *strtab, char *name);
int coffsym_search(Section *symtab, char *name);
void coffreloc_add(Section *sec, Symbol *sym, int offset, char type);
void coffreloc_direct_add(int offset, int cfsym, char section, char type);
void init_coff();
void free_sections();
void write_obj(char *name);
void fpad(FILE *fp,int new_pos);


#endif